-module(xbt_access_server).

-behaviour(gen_server).

-export([init/1,handle_call/3,handle_cast/2,
         handle_info/2,terminate/2,code_change/3]).

-export([start/0,start_link/0]).

-include("xbt.hrl").


start()           ->
    gen_server:start(?MODULE,[],[]).

start_link()           ->
    gen_server:start_link({local,?MODULE},?MODULE,[],[]).

init([])    ->
    Access = xbt_config:get_config(access),
    Users  = xbt_config:get_config(users),
    stop_access_mod(Access),
    start_access_mod(Access),
    {ok,{Access,Users}}.

start_access_mod([]) ->
    ok;
start_access_mod([Access_mod|Tail]) ->
    case Access_mod of
        {tcp,{Listen,Port,MaxConns,WSize}}  ->
            F = fun(Socket) -> xbt_tcp_callback:conn_entry(Socket,WSize) end,
            {ok,_} = xbt_tcp_server:start(Listen,Port,F,MaxConns);
        _                                   ->
            ok
    end,
    start_access_mod(Tail).

stop_access_mod([]) ->
    ok;
stop_access_mod([Access_mod|Tail]) ->
    case Access_mod of
        {tcp,{Listen,Port,_,_}}  ->
            xbt_tcp_server:stop(Listen,Port);
        _                        ->
            ok
    end,
    stop_access_mod(Tail).

terminate(normal,{Access,_})   ->
    stop_access_mod(Access).

handle_cast(_Msg, State) ->
    {noreply,State}.

%% user auth service
handle_call({checkuser,{User,Auth,Time}},_From,State) ->
    {_,Users} = State,
    Resp = check_user(User,Auth,Time,Users),
    {reply,Resp,State};

handle_call(_Msg,_From,State) ->
    {reply,ok,State}.

handle_info(_Info, State) ->
    {noreply, State}.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

check_user(User,AuthCode,TimeStamp,Users) when is_list(Users)   ->
    ?DEBUG("[~p]check user: ~p, known users: ~p~n",[self(),User,Users]),
    User1 = [U1 || U1 <- binary_to_list(User),U1 > 0],
    ?DEBUG("[~p]real User is: ~p~n",[self(),User1]),
    case [ Pass || {U1,Pass} <- Users,U1 == User1 ] of
        []       ->
            ?DEBUG("[~p]checkuser: no such user:~p~n",[self(),User1]),
            {error,nosuchuser};
        [Pass]   ->
            Md5in = list_to_binary([User1,Pass,TimeStamp]),
%            crypto:start(),
            Md5out = crypto:md5(Md5in),
%            crypto:stop(),
            if
                Md5out =:= AuthCode  ->
                    ok;
                true                 ->
                    {error,passwd}
            end
    end.
